﻿#pragma once
#include "Comm.h"

namespace COMM
{
	class COMM_API TlsVarFactory
	{
	public:
		virtual ~TlsVarFactory() {}
		virtual void Release() { delete this; }
		virtual void* Create() = 0;
		virtual void Destroy(void* val) = 0;
	};

	template<class T>
	class CommTlsVarFactory : public TlsVarFactory
	{
	public:
		virtual void* Create() { return new T(); }
		virtual void Destroy(void* val) { delete (T*)val; }
	};

	template<class T, class P>
	class ParamTlsVarFactory : public TlsVarFactory
	{
	public:
		ParamTlsVarFactory(P* param = NULL): m_param(param) {}
		void SetParam(P* param) { if (NULL != m_param) { Destroy(m_param); } m_param = param; }
		virtual void* Create() { return new T(m_param); }
		virtual void Destroy(void* val) { delete (T*)val; }
	private:
		P* m_param;
	};

	// destroy TLS value associated with key automatically while thread exit.
	//
	class COMM_API TlsVar
	{
	public:
#ifdef COMM_MSVC
		typedef DWORD TlsKey;
#else
		typedef pthread_key_t TlsKey;
#endif

		TlsVar(TlsVarFactory* factory);
		virtual ~TlsVar();
		TlsVarFactory* Factory();
		TlsKey Key();
		void* Value();
		
	private:
		TlsVarFactory* m_factory;
		TlsKey m_key;
	};

	template<class T>
	class LocalVar : public TlsVar
	{
	public:
		LocalVar() : TlsVar(new CommTlsVarFactory<T>()) {}
		T* get() { return (T*)Value(); }
	};

	template<class T, class P>
	class ParamLocalVar : public TlsVar
	{
	public:
		ParamLocalVar(P* param = NULL) : TlsVar(new ParamTlsVarFactory<T,P>(param)) {}
		void SetParam(P* param) { ((ParamTlsVarFactory<T, P>*)Factory())->SetParam(param);}
		T* get() { return (T*)Value(); }
	};
}


